#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "string.h"
#include "driver/gpio.h"

#include "cmd.h"

#define UART_NUM        UART_NUM_0      // 使用 UART0
#define BUF_SIZE        (254)          // DMA 缓冲区大小
#define RD_BUF_SIZE     (BUF_SIZE / 2)  // 单次读取最大长度
static const char *TAG = "MyDebugCMD";

#define		MEUNHEAD							"/************************************MENU************************************/\r\n"
#define		MENUTIP1							"/************************************TIPS************************************/"
#define		MENUTIP2							"/****set or action parameter need config data type,can use int and float****/"
#define		MENUSET								"1.set menu\r\n"
#define		MENUGET								"2.get menu\r\n"
#define		MENUACTION							"3.action menu\r\n"

#define		TYPE_FLOAT							"float"
#define		TYPE_INT							"int"
#define		TYPE_CHAR							"char"

const char* RootDirectory[InsNum] = { "help","set","get","action" };

CmdHandle_t CmdHandle;

static int8_t CMDAnalyse(const char* packet, char** argv);
static void CMDProtocol(CmdHandle_t* CmdHandle);

void uart0_dma_init() {
    // UART 配置
    uart_config_t uart_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_DEFAULT,
    };
    ESP_ERROR_CHECK(uart_param_config(UART_NUM, &uart_config));

    // 设置 UART0 引脚（GPIO3=RX, GPIO1=TX）
    ESP_ERROR_CHECK(uart_set_pin(UART_NUM, GPIO_NUM_1, GPIO_NUM_3, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));

    // 安装 UART 驱动（DMA 模式）
    ESP_ERROR_CHECK(uart_driver_install(
        UART_NUM,           // UART 端口号
        BUF_SIZE,       // RX 缓冲区大小（DMA 需要双缓冲）
        BUF_SIZE,       // TX 缓冲区大小（设为 0 可禁用 TX）
        0,                  // 事件队列大小（0 表示不使用事件）
        NULL,               // 事件队列句柄
        0                   // 中断分配标志（0 表示默认）
    ));
}


CmdHandle_t CmdHandle;


void uart0_rx_task(void *pvParameters) {
    // CmdHandle_t CmdHandle;
    char* argv[MaxInsLen];
    uart0_dma_init();
    uint8_t *data = (uint8_t *)malloc(RD_BUF_SIZE + 1);  // +1 用于字符串终止符
    while (1) {
        // 从 UART 环形缓冲区读取数据
        int len = uart_read_bytes(UART_NUM, data, RD_BUF_SIZE, pdMS_TO_TICKS(100));
        if (len > 0) 
        {
			char result[len];
			strncpy(result, (const char *)data, len);
            uint8_t argcnt = CMDAnalyse((const char *)result, CmdHandle.argv);
            if ((argcnt != 2) && (argcnt != 1) && (argcnt != 3) && (argcnt != 4))
            {
				ESP_LOGI(TAG, "receive data len is:%d",argcnt);
            }
            else
            {
                CmdHandle.argc = argcnt;
                CMDProtocol(&CmdHandle);
            }
        }
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }

    free(data);
    vTaskDelete(NULL);
}

bool MyCMDRegisterIns(CmdHandle_t* CmdHandle, InsType_t type, char* Ins, void (*CB)(void*))
{
	if (type == InsHelp)
	{
		return 0;
	}
	if (CmdHandle->CmdIns[type].effInsNum < MaxInsNum)
	{
		strcpy(CmdHandle->CmdIns[type].Ins[CmdHandle->CmdIns[type].effInsNum], Ins);
		CmdHandle->CmdIns[type].cmdCB[CmdHandle->CmdIns[type].effInsNum] = CB;
		CmdHandle->CmdIns[type].effInsNum += 1;
		return 1;
	}
	return 0;
}

static int8_t CMDAnalyse(const char* packet, char** argv)
{
	char* token;
	uint8_t argvc = 0;
	/* 获取第一个子字符串 */
	token = strtok((char*)packet, " ");
	if (strlen(token) > CMDSTRLEN)
	{
		return -1;
	}
	/* 继续获取其他的子字符串 */
	while (token != NULL) {
		if (argvc > CMDARGVLEN)
		{
			return -2;
		}
		if (strlen(token) > CMDSTRLEN)
		{
			return -1;
		}
		argv[argvc++] = token;
		token = strtok(NULL, " ");
	}
	return argvc;
}

static void CMDProtocol(CmdHandle_t* CmdHandle)
{
	if (strncmp(CmdHandle->argv[0], RootDirectory[InsHelp], strlen(RootDirectory[InsHelp])) == 0)
	{
		char buf[30];
		uart_write_bytes(UART_NUM, "\r\n", strlen("\r\n"));
		uart_write_bytes(UART_NUM, MEUNHEAD, strlen(MEUNHEAD));
		uart_write_bytes(UART_NUM, MENUSET, strlen(MENUSET));
		for (uint8_t i = 0; i < CmdHandle->CmdIns[InsSet].effInsNum; i++)
		{
			sprintf(buf, "    %d", i + 1);
			uart_write_bytes(UART_NUM, buf, strlen(buf));
			uart_write_bytes(UART_NUM, ".", strlen("."));
			uart_write_bytes(UART_NUM, CmdHandle->CmdIns[InsSet].Ins[i], strlen(CmdHandle->CmdIns[InsSet].Ins[i]));
			uart_write_bytes(UART_NUM, "\r\n", strlen("\r\n"));
		}
		uart_write_bytes(UART_NUM, MENUGET, strlen(MENUGET));
		for (uint8_t i = 0; i < CmdHandle->CmdIns[InsGet].effInsNum; i++)
		{
			sprintf(buf, "    %d", i + 1);
			uart_write_bytes(UART_NUM, buf, strlen(buf));
			uart_write_bytes(UART_NUM, ".", strlen("."));
			uart_write_bytes(UART_NUM, CmdHandle->CmdIns[InsGet].Ins[i], strlen(CmdHandle->CmdIns[InsGet].Ins[i]));
			uart_write_bytes(UART_NUM, "\r\n", strlen("\r\n"));
		}
		uart_write_bytes(UART_NUM, MENUACTION, strlen(MENUACTION));
		for (uint8_t i = 0; i < CmdHandle->CmdIns[InsAction].effInsNum; i++)
		{
			sprintf(buf, "    %d", i + 1);
			uart_write_bytes(UART_NUM, buf, strlen(buf));
			uart_write_bytes(UART_NUM, ".", strlen("."));
			uart_write_bytes(UART_NUM, CmdHandle->CmdIns[InsAction].Ins[i], strlen(CmdHandle->CmdIns[InsAction].Ins[i]));
			uart_write_bytes(UART_NUM, "\r\n", strlen("\r\n"));
		}
		uart_write_bytes(UART_NUM, MENUTIP1, strlen(MENUTIP1));
        uart_write_bytes(UART_NUM, "\r\n", strlen("\r\n"));
		uart_write_bytes(UART_NUM, MENUTIP2, strlen(MENUTIP2));
        uart_write_bytes(UART_NUM, "\r\n", strlen("\r\n"));
	}
	else if (strncmp(CmdHandle->argv[0], RootDirectory[InsSet], strlen(RootDirectory[InsSet])) == 0)
	{
		for (uint8_t i = 0; i < CmdHandle->CmdIns[InsSet].effInsNum; i++)
		{
			if (strncmp(CmdHandle->CmdIns[InsSet].Ins[i], CmdHandle->argv[1], strlen(CmdHandle->CmdIns[InsSet].Ins[i])) == 0)
			{
				if (CmdHandle->argc == 4)
				{
					if (strcmp(TYPE_FLOAT, CmdHandle->argv[2]) == 0)
					{
						char* endptr;
						float data = strtof(CmdHandle->argv[3], &endptr);
						if (CmdHandle->argv[3] != endptr)
						{
							CmdHandle->CmdIns[InsSet].cmdCB[i](&data);
						}
					}
					else if (strcmp(TYPE_INT, CmdHandle->argv[2]) == 0)
					{
						int data = atoi(CmdHandle->argv[3]);
						CmdHandle->CmdIns[InsSet].cmdCB[i](&data);
					}
					else if (strcmp(TYPE_CHAR, CmdHandle->argv[2]) == 0)
					{
						CmdHandle->CmdIns[InsSet].cmdCB[i]((void*)CmdHandle->argv[3]);
					}
				}
				else if(CmdHandle->argc == 2)
				{
					CmdHandle->CmdIns[InsSet].cmdCB[i](NULL);
				}
				return;
			}
		}
	}
	else if (strncmp(CmdHandle->argv[0], RootDirectory[InsGet], strlen(RootDirectory[InsGet])) == 0)
	{
		// ESP_LOGI(TAG, "into get level 1,get meun num is:%d", CmdHandle->CmdIns[InsGet].effInsNum);
		for (uint8_t i = 0; i < CmdHandle->CmdIns[InsGet].effInsNum; i++)
		{
			if (strncmp(CmdHandle->CmdIns[InsGet].Ins[i], CmdHandle->argv[1], strlen(CmdHandle->CmdIns[InsGet].Ins[i])) == 0)
			{
				if (CmdHandle->argc == 4)
				{
					if (strcmp(TYPE_FLOAT, CmdHandle->argv[2]) == 0)
					{
						char* endptr;
						float data = strtof(CmdHandle->argv[3], &endptr);
						if (CmdHandle->argv[3] != endptr)
						{
							CmdHandle->CmdIns[InsGet].cmdCB[i](&data);
						}
					}
					else if (strcmp(TYPE_INT, CmdHandle->argv[2]) == 0)
					{
						int data = atoi(CmdHandle->argv[3]);
						CmdHandle->CmdIns[InsGet].cmdCB[i](&data);
					}
					else if (strcmp(TYPE_CHAR, CmdHandle->argv[2]) == 0)
					{
						CmdHandle->CmdIns[InsGet].cmdCB[i]((void*)CmdHandle->argv[3]);
					}
				}
				else if(CmdHandle->argc == 2)
				{
					CmdHandle->CmdIns[InsGet].cmdCB[i](NULL);
				}
				return;
			}
		}
	}
	else if (strncmp(CmdHandle->argv[0], RootDirectory[InsAction], strlen(CmdHandle->argv[0])) == 0)
	{
		for (uint8_t i = 0; i < CmdHandle->CmdIns[InsAction].effInsNum; i++)
		{
			if (strncmp(CmdHandle->CmdIns[InsAction].Ins[i], CmdHandle->argv[1], strlen(CmdHandle->CmdIns[InsAction].Ins[i])) == 0)
			{
				if (CmdHandle->argc == 4)
				{
					if (strcmp(TYPE_FLOAT, CmdHandle->argv[2]) == 0)
					{
						char* endptr;
						float data = strtof(CmdHandle->argv[3], &endptr);
						if (CmdHandle->argv[3] != endptr)
						{
							CmdHandle->CmdIns[InsAction].cmdCB[i](&data);
						}
					}
					else if (strcmp(TYPE_INT, CmdHandle->argv[2]) == 0)
					{
						int data = atoi(CmdHandle->argv[3]);
						CmdHandle->CmdIns[InsAction].cmdCB[i](&data);
					}
					else if (strcmp(TYPE_CHAR, CmdHandle->argv[2]) == 0)
					{
						CmdHandle->CmdIns[InsAction].cmdCB[i]((void*)CmdHandle->argv[3]);
					}
				}
				else if (CmdHandle->argc == 2)
				{
					CmdHandle->CmdIns[InsAction].cmdCB[i](NULL);
				}
				return;
			}
		}
	}
	else
	{
		uart_write_bytes(UART_NUM, "unvalid cmd\r\n", strlen("unvalid cmd\r\n"));
	}
}